if (false) {
  class Test {
    // 1. 在类中直接定义的方法会绑定到类的原型中 Test.prototype.{ test() {} }
    test() {
      console.log('我是测试方法', this);
    }

    // 2. 类中使用 static 定义的方法会绑定到类的构造函数中 Test.{ test2() {} } 相当于在类上直接添加方法
    static test2() {
      console.log('我是测试方法2', this);
    }

    constructor() {
      // 3. this.test 相当于在 new Test() 的对象实例上直接绑定一个 test 方法，优先级肯定是要高于去原型上找的，这一点可以去看我的原型、原型链的文档 __proto__ 找原型链，找到某一个对象上的 prototype 的 __proto__ 为 null，原型链查找完毕
      this.test = function () {
        console.log("我是constructor中的测试方法");
        console.log(this);
      }
    }
  }

  // Test.prototype.test1 = function test1() {
  //   console.log('我是测试方法1');
  // }

  // Test.test3 = function () {
  //   console.log('我是测试方法3');
  // }

  const test = new Test();

  test.test();
  // test.test1();
  // test.test2();
  // console.log(Test);  
}

if (true) {
  class Father {
    constructor() {
      this.name = 'Father';
    }

    say() {
      console.log('Hello');
    }
  }

  class Son extends Father {
    constructor() {
      // 4. super() 函数实际上就是做了一次父类的 new Father()，创建除了一个实例对象，将父类 this 上的属性或方法绑定到了这个实例对象上，子类之所以不能在 super() 方法前去定义 this 上的属性，就是为了避免说出现两个不同的对象，保持一个，super() 执行完毕后，执行子类的 this 绑定，把子类的元素绑定到之前创建的那个实例对象中，合在一起。
      super();
      this.age = 12;
    }

    study() {
      // 1. 首先实例化出来一个实例对象 son ，son 对象上并没有 say() 甚至于没有 study() ，这时先去属性 __proto__ 上找 Son 的 prototype（原型），发现了 study() ，直接调用
      // 2. 调用到内部 this.say() 发现没有 say() ，又去 Son 的 prototype 的 __proto__ 上找，也是就继承于 Son 类的 Father 的 prototype ，找到了 say()，直接调用
      // 3. 总结下来就是一个通过 __proto__（原型链）的方法找到被继承的属性或方法吧，查找过程如下
      // son.__proto__ 找到 study()
      // son.__proto__.__proto__ 找到 say()
      this.say(); // Hello
    }
  }

  const son = new Son();
  son.study();
  console.log(son);

  // 佐证: 原型链相等
  console.log(son.__proto__ === Son.prototype); // true
  console.log(son.__proto__.__proto__ === Father.prototype); // true
}